#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
import shutil
import hashlib

def throw_compilation_error(error_string):
    sys.exit("{0}:1:error ProtobufROSgen: {1}\n".format(sys.argv[1], error_string))

def read_file_content(file_path):
    """
    从文件中读取内容。
    
    :param file_path: 文件路径
    :return: 文件内容或在出错时返回空字符串
    """
    # 获取当前脚本文件的目录
    current_script_dir = os.path.dirname(os.path.abspath(__file__))
    # 构建完整的文件路径
    full_path = os.path.join(current_script_dir, file_path)
    
    try:
        with open(full_path, 'r') as file:
            # 读取文件的全部内容
            content = file.read()
            return content
    except Exception as e:
        print("read_file_content error: {}".format(e))
        return ""

def write_to_file(file_path, file_data):
    """
    将数据写入文件，并确保文件目录存在。
    
    :param file_path: 文件路径
    :param file_data: 要写入的数据
    """
    create_directory(os.path.dirname(file_path))
    with open(file_path, 'w') as f:
        f.write(file_data)

def check_and_create_file(file_path):
    """
    检查并创建文件，并确保文件目录存在。
    
    :param file_path: 文件路径
    """
    create_directory(os.path.dirname(file_path))
    # 检查文件是否存在，如果不存在则创建文件
    if not os.path.exists(file_path):
        with open(file_path, 'w') as file:
            pass  # 创建一个空文件

def create_directory(dir_path):
    """
    创建目录，如果目录不存在的话。
    
    :param dir_path: 目录路径
    """
    if not os.path.exists(dir_path):
        os.makedirs(dir_path)

def delete_directory(dir_path):
    """
    删除目录。
    
    :param dir_path: 目录路径
    """
    try:
        shutil.rmtree(dir_path)
    except Exception as e:
        print("create_directory error: {},{}".format(dir_path).format(e))

def move_file(src_file_path, new_file_path):
    """
    移动文件。
    
    :param src_file_path: 源文件路径
    :param new_file_path: 目标文件路径
    """
     # 获取新文件路径的目录
    new_directory = os.path.dirname(new_file_path)
    
    # 确保新目录存在
    if not os.path.exists(new_directory):
        os.makedirs(new_directory)
    
    try:
        # 尝试移动文件
        shutil.move(src_file_path, new_file_path)
    except shutil.Error as e:
        # 捕获并处理shutil.Error
        print("Error moving file: {}".format(e))
    except OSError as e:
        # 捕获并处理OSError
        print("OS error: {}".format(e))
    except Exception as e:
        # 捕获并处理所有其他异常
        print("Unexpected error: {}".format(e))

def copy_file(src_file_path, new_file_path):
    """
    复制文件。
    
    :param src_file_path: 源文件路径
    :param new_file_path: 目标文件路径
    """
    # 获取新文件路径的目录
    new_directory = os.path.dirname(new_file_path)
    
    # 确保新目录存在
    if not os.path.exists(new_directory):
        os.makedirs(new_directory)
    
    try:
        # 尝试拷贝文件
        shutil.copy(src_file_path, new_file_path)
    except shutil.Error as e:
        # 捕获并处理shutil.Error
        print("Error copying file: {}".format(e))
    except OSError as e:
        # 捕获并处理OSError
        print("OS error: {}".format(e))
    except Exception as e:
        # 捕获并处理所有其他异常
        print("Unexpected error: {}".format(e))

def replace_msg_content(template, proto_file_name, pkg_name, class_name):
    """
    替换模板中的占位符。
    
    :param template: 模板文本
    :param proto_file_name: Protobuf 文件名
    :param pkg_name: 包名
    :param class_name: 类名
    :return: 替换后的文本
    """
    print("pkg_name2 "   + pkg_name)
    print("class_name "   + class_name)
    checksum = hashlib.md5("%s::%s" %(pkg_name, class_name)).hexdigest()
    requestChecksum = hashlib.md5("%s::%s" %(pkg_name, proto_file_name+"Request")).hexdigest()
    responseChecksum = hashlib.md5("%s::%s" %(pkg_name, proto_file_name+"Response")).hexdigest()
    result = (template.replace("@PROTO_H@", proto_file_name)
                      .replace("@PROTO_PY@", proto_file_name+"_pb2")
                      .replace("@Class@", class_name)
                      .replace("@Package@", pkg_name)
                      .replace("@Checksum@", checksum)
                      .replace("@ChecksumRequest@", requestChecksum)
                      .replace("@ChecksumResponse@", responseChecksum))
    return result

def replace_file_content(template_file, proto_file_name, pkg_name, class_name):
    """
    读取模板文件并替换内容。
    
    :param template_file: 模板文件路径
    :param proto_file_name: Protobuf 文件名
    :param pkg_name: 包名
    :param class_name: 类名
    :return: 替换后的文本
    """
    content = read_file_content(template_file)
    return replace_msg_content(content, proto_file_name, pkg_name, class_name)

def write_file_content(target_file, template_file,proto_file_name, pkg_name, class_name):
    """
    将替换后的模板内容写入目标文件。
    
    :param target_file: 目标文件路径
    :param template_file: 模板文件路径
    :param proto_file_name: Protobuf 文件名
    :param pkg_name: 包名
    :param class_name: 类名
    """
    content = replace_file_content(template_file, proto_file_name, pkg_name, class_name)
    write_to_file(target_file, content)


def create_init_files(out_dir, proto_file_name, msg_type):
    """
    创建python的包声明文件。
    
    :param out_dir: 输出目录
    :param proto_file_name: Protobuf 文件名
    :param msg_type: 消息类型（"msg" /"srv"/ "action"）
    """
    root_init ='{}/../__init__.py'.format(out_dir)
    check_and_create_file(root_init)

    pkg_init ='{}/__init__.py'.format(out_dir)
    check_and_create_file(pkg_init)
    append_init_files(pkg_init, 'from .%s_pb2 import *\n' % proto_file_name)
    if msg_type == "action":
        action_imports = [
            "from ._{0}Action import *",
            "from ._{0}ActionFeedback import *",
            "from ._{0}ActionGoal import *",
            "from ._{0}ActionResult import *",
            "from ._{0}Feedback import *",
            "from ._{0}Goal import *",
            "from ._{0}Result import *"
        ]
        for import_template in action_imports:
            append_init_files(pkg_init, import_template.format(proto_file_name)+"\n")
    else:
        append_init_files(pkg_init, 'from ._%s import *\n' % proto_file_name)


def append_init_files(init_file,append_str): 
    """
    检查python的包声明中是否包含相应声明，未包含时追加。
    
    :param init_file: 包声明文件
    :param append_str: 需追加的import语句
    """
    # 如果文件存在但不包含 append_str，则追加
    if append_str not in open(init_file, 'r').read():
      with open(init_file, 'a') as f:
          f.write(append_str)